/* Copyright [2023] <gyl> */

#include "sql/executor/grant_executor.h"

#include "common/global_context.h"
#include "common/log/log.h"
#include "event/session_event.h"
#include "event/sql_event.h"
#include "session/session.h"
#include "sql/executor/utils.h"
#include "sql/identifier/identify_stage.h"
#include "sql/parser/parse.h"
#include "sql/stmt/grant_stmt.h"
#include "sql/stmt/insert_stmt.h"
#include "sql/stmt/update_stmt.h"
#include "storage/db/db.h"
#include "storage/default/default_handler.h"
#include "storage/table/table.h"

RC GrantExecutor::execute(SQLStageEvent *sql_event) {
  RC rc = RC::SUCCESS;
  ExecutorUtils utils;
  DefaultHandler &handler = DefaultHandler::get_default();
  Db *db = handler.find_db("manager");
  sql_event->set_flag_permit();
  Stmt *stmt = sql_event->stmt();
  ASSERT(stmt->type() == StmtType::GRANT,
         "grant executor can not run this command: %d",
         static_cast<int>(stmt->type()));

  GrantStmt *grant_stmt = static_cast<GrantStmt *>(stmt);

  int **operation = grant_stmt->operation();
  std::vector<std::string> users = grant_stmt->users();
  std::vector<std::string> relations = grant_stmt->table_names();
  int priv = grant_stmt->priv();
  for (int i = 0; i < users.size(); i++) {
    for (int j = 0; j < relations.size(); j++) {
      if (operation[i][j] == 0) {  // insert
        std::string sql = "insert into tables_priv values('" + users[i] +
                          "', '" + relations[j] + "' ," + std::to_string(priv) +
                          ")";
        ParsedSqlResult parsed_sql_result;
        parse(sql.c_str(), &parsed_sql_result);
        std::unique_ptr<ParsedSqlNode> sql_node =
            std::move(parsed_sql_result.sql_nodes().front());
        Stmt *insert_stmt;
        InsertSqlNode insert = sql_node->insertion;
        rc = InsertStmt::create(db, insert, insert_stmt);
        if (rc != RC::SUCCESS) {
          return rc;
        }
        rc = utils.operate_priv_record(insert_stmt, db);
        if (rc != RC::SUCCESS) {
          return rc;
        }
      } else if (operation[i][j] == 1) {  // update
        int pre_priv;
        IdentifyStage::get_priv(db, users[i], relations[j], pre_priv);
        priv |= pre_priv;
        std::string sql =
            "update tables_priv set priv = " + std::to_string(priv) +
            " where table_name = '" + relations[j] + "' and user = '" +
            users[i] + "'";
        ParsedSqlResult parsed_sql_result;
        parse(sql.c_str(), &parsed_sql_result);
        std::unique_ptr<ParsedSqlNode> sql_node =
            std::move(parsed_sql_result.sql_nodes().front());
        Stmt *update_stmt;
        UpdateSqlNode update = sql_node->update;
        rc = UpdateStmt::create(db, update, update_stmt);
        if (rc != RC::SUCCESS) {
          return rc;
        }
        rc = utils.operate_priv_record(update_stmt, db);
        if (rc != RC::SUCCESS) {
          return rc;
        }
      }
    }
  }
  sql_event->set_flag_identify();
  return rc;
}
